from typing import Any

from aiogram import Bot, types
from aiogram_dialog import Dialog, DialogManager, Window
from aiogram_dialog.widgets.input import TextInput
from aiogram_dialog.widgets.kbd import Button, Cancel, Url
from aiogram_dialog.widgets.text import Format
from sqlalchemy.ext.asyncio import AsyncSession

from app.bot.dialog.dialog_states import PaymentSG
from app.bot.dialog.widgets import LocaleText
from app.bot.services.broadcaster import broadcast
from app.bot.services.helpers import get_rate_usd
from app.bot.services.locale import Locale
from app.bot.services.loggers import logger
from app.bot.services.paypalych_api.client import PayPalychClient
from app.config import Settings
from app.database.services.payments import create_payment, update_payment
from app.database.services.stats import update_stats
from app.database.services.users import increase_user_balance


async def check_payment(call: types.CallbackQuery, widget: Any, manager: DialogManager):

    db_session: AsyncSession = manager.middleware_data.get("db_session")
    locale: Locale = manager.middleware_data.get("locale")
    payment_client: PayPalychClient = manager.middleware_data.get("payment_client")
    bot: Bot = manager.middleware_data.get("bot")
    config: Settings = manager.middleware_data.get("config")
    bill_id = manager.dialog_data.get("bill_id")
    payment_id = manager.dialog_data.get("payment_id")
    user_id: int = call.from_user.id
    usd_summ: float = manager.dialog_data.get("usd_summ")

    try:
        bill = await payment_client.get_bill(bill_id)

        bill_status = bill.get("status")

        if not bill_status:
            await call.answer(locale.get("error-msg"))

        if bill_status == "NEW":
            await call.answer(locale.get("payment-waiting"))

        elif bill_status == "SUCCESS":
            await call.answer(locale.get("payment-successful"))
            await update_payment(db_session, payment_id, status="paid")
            await increase_user_balance(
                db_session, user_id, usd_summ
            )  # Пополняем баланс юзера на сумму в $
            await update_stats(db_session, payments_payed=1)
            await manager.done()

        elif bill_status == "FAIL":
            await call.message.answer(locale.get("payment-fail", payment_id=payment_id))
            await update_payment(db_session, payment_id, status="payment_failed")
            await manager.done()

    except Exception as e:
        await call.answer(locale.get("error-msg"))
        logger.exception(e)
        await broadcast(
            bot,
            [config.tg_bot.developer_id],
            f"Ошибка во время проверки оплаты: {str(e)}",
        )


async def set_payment_amount(
    message: types.Message, widget: Any, manager: DialogManager, selected_amount: str
):

    db_session = manager.middleware_data.get("db_session")
    payment_client: PayPalychClient = manager.middleware_data.get("payment_client")
    bot: Bot = manager.middleware_data.get("bot")
    config: Settings = manager.middleware_data.get("config")
    user_id: int = message.from_user.id
    locale: Locale = manager.middleware_data.get("locale")
    usd_rate: float = manager.dialog_data.get("usd_rate")

    try:
        summ: float = float(selected_amount)
        payment_summ = round(
            summ * usd_rate, 2
        )  # Конвертируем доллары в рубли и округляем

        payment = await create_payment(db_session, payment_summ, user_id)
        bill = await payment_client.create_bill(
            amount=payment_summ, order_id=payment.id
        )

        if not bill:
            await message.answer(locale.get("error-msg"))
            return

        payment.bill_id = bill.get("bill_id")

        logger.info(f"Создан новый счет {bill}")
        logger.info(
            f"Добавлена новая оплата №{payment.id} на сумму {payment.summ} руб.s"
        )

        manager.dialog_data["usd_summ"] = summ
        manager.dialog_data["payment_summ"] = payment_summ
        manager.dialog_data["payment_id"] = payment.id
        manager.dialog_data["bill_id"] = bill.get("bill_id")
        manager.dialog_data["bill_link"] = bill.get("link_page_url")
        await db_session.commit()

        await manager.switch_to(PaymentSG.create_payment)
    except ValueError:
        await message.answer(locale.get("summ-wrong-format"))
    except Exception as e:
        logger.exception(e)
        await message.answer(locale.get("error-msg"))
        await broadcast(
            bot,
            [config.tg_bot.developer_id],
            f"Ошибка во время создания счета для оплаты: {str(e)}",
        )


async def get_usd_rate(dialog_manager: DialogManager, **kwargs):
    usd_rate = await get_rate_usd()
    dialog_manager.dialog_data["usd_rate"] = usd_rate

    return {"usd_rate": usd_rate}


set_amount_window = Window(
    LocaleText("select-payment-amount", usd_rate="{usd_rate}"),
    TextInput("payment_amount", str, on_success=set_payment_amount),
    Cancel(LocaleText("back-btn")),
    state=PaymentSG.select_amount,
    getter=get_usd_rate,
)

check_payment_window = Window(
    LocaleText("payment-msg", payment_summ="{dialog_data[payment_summ]}"),
    Url(LocaleText("pay-btn"), Format("{dialog_data[bill_link]}")),
    Button(
        LocaleText("check-payment-btn"), id="check_payment_btn", on_click=check_payment
    ),
    state=PaymentSG.create_payment,
)

payment_dialog = Dialog(set_amount_window, check_payment_window)
